using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace VRB_0._1
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        KeyboardState currentKeyboardState;
        KeyboardState previousKeyboardState;
        
        Map currentMap;

        Avatar avatar;

        SpriteFont LevelEndFont;
        String winText = "";

        GameState currentGameState;

        MenuScreen menu;
        OptionsScreen optionsScreen;
        MapSelectScreen mapSelectScreen;
        PauseScreen pauseScreen;

        Song menuSong, gameSong;
        SoundEffect ekslosjonslyd;
        
        SoundEffect select;
        SoundEffect back;

        Boolean musicEnabled = true;

        public enum GameState
        {
            MAINMENU,
            MAPSELECT,
            GAME,
            DEAD,
            OPTIONS,
            PAUSE,
            EXIT
        }

        public enum ENDING
        {
            WIN,
            LOSE,
            NOTYET
        }

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            menu = new MenuScreen();
            optionsScreen = new OptionsScreen();
            pauseScreen = new PauseScreen();
            mapSelectScreen = new MapSelectScreen();

            currentGameState = GameState.MAINMENU;

            avatar = new Avatar();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            menu.Initialize(Content);
            optionsScreen.Initialize(Content);
            pauseScreen.Initialize(Content);
            mapSelectScreen.Initialize(Content);

            LevelEndFont = Content.Load<SpriteFont>("gameFont");

            menuSong = Content.Load<Song>("menusong");
            gameSong = Content.Load<Song>("gamesong");
            ekslosjonslyd = Content.Load<SoundEffect>("explosjonslyd");
            select = Content.Load<SoundEffect>("select");
            back = Content.Load<SoundEffect>("back");

            this.PlayMusic(menuSong);
        }
        protected override void UnloadContent()
        {

        }
        protected override void Update(GameTime gameTime)
        {
            switch (currentGameState)
            {
                case GameState.GAME:
                    this.takeInput();
                    this.updateGravity();
                    this.updateAvatarCollisions();
                    this.updateEnemyCollisions();

                    if(avatar.Position.X> avatar.lastPosition.X)
                    {
                        currentMap.UpdateMap(avatar.MoveSpeed, true);
                    }
                    else if(avatar.Position.X< avatar.lastPosition.X)
                    {
                        currentMap.UpdateMap(avatar.MoveSpeed, false);
                    }
                    currentMap.Update(gameTime);

                    avatar.Update(gameTime);

                    this.checkForLevelEnd();
                    break;
                case GameState.DEAD:
                    avatar.Update(gameTime);
                    this.takeInput();
                    break;
                case GameState.MAINMENU:
                    this.takeInput();
                    break;
                case GameState.OPTIONS:
                    this.takeInput();
                    break;
                case GameState.MAPSELECT:
                    this.takeInput();
                    break;
                case GameState.PAUSE:
                    this.takeInput();
                    break;
                case GameState.EXIT:
                    this.Exit();
                    break;
            }

            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin();

            switch (currentGameState)
            {
                case GameState.GAME:
                    
                    currentMap.Draw(spriteBatch);
                    avatar.Draw(spriteBatch);

                    spriteBatch.DrawString(LevelEndFont, winText,
                        new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y + 30), Color.White);
                    break;
                case GameState.DEAD:
                    currentMap.Draw(spriteBatch);
                    avatar.Draw(spriteBatch);

                    spriteBatch.DrawString(LevelEndFont, winText,
                        new Vector2(GraphicsDevice.Viewport.TitleSafeArea.X, GraphicsDevice.Viewport.TitleSafeArea.Y + 30), Color.White);
                    break;
                case GameState.MAINMENU:
                    menu.Draw(spriteBatch, GraphicsDevice.Viewport);
                    break;
                case GameState.OPTIONS:
                    optionsScreen.Draw(spriteBatch, GraphicsDevice.Viewport);
                    break;
                case GameState.MAPSELECT:
                    mapSelectScreen.Draw(spriteBatch, GraphicsDevice.Viewport);
                    break;
                case GameState.PAUSE:
                    pauseScreen.Draw(spriteBatch, GraphicsDevice.Viewport);
                    break;
            }

            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void updateAvatarCollisions()
        {
            Rectangle rect1, rect2;

            rect1 = new Rectangle((int)avatar.Position.X, (int)avatar.Position.Y,
                avatar.Width, avatar.Height);
            //currentMap.CheckForCollisions(avatar);
            
            foreach (VisualObject thing in currentMap.objects)
            {
                rect2 = new Rectangle((int)thing.Position.X - thing.Width / 2, (int)thing.Position.Y - thing.Height / 2, thing.Width, thing.Height);
                if (!(thing is Button) && !(thing is GaffaSpawner) && rect1.Intersects(rect2))
                {
                    if (avatar.direction == Avatar.Direction.RIGHT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                        avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X - thing.Width / 2 - avatar.Width);
                    else if (avatar.direction == Avatar.Direction.LEFT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                        avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X + thing.Width / 2);
                    else if (avatar.action == Avatar.Action.JUMPING)
                        avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y + thing.Height / 2);
                    else
                        avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y - thing.Height / 2 - avatar.Height);
                }
                else if (thing is Button)
                {
                    rect2 = new Rectangle((int)((Button)thing).Position.X, (int)((Button)thing).Position.Y, thing.Width, thing.Height);
                    Button.State lastState = ((Button)thing).currentState;

                    if (rect1.Intersects(rect2))
                    {
                        ((Button)thing).currentState = Button.State.ON;
                        if (lastState != Button.State.ON)
                        {
                            currentMap.changeButtonState();
                            thing.Position.Y += 10;
                        }
                        if (avatar.direction == Avatar.Direction.RIGHT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                            avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X - thing.Width / 2 - avatar.Width);
                        else if (avatar.direction == Avatar.Direction.LEFT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                            avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X + thing.Width / 2);
                        else if (avatar.action == Avatar.Action.JUMPING)
                            avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y + thing.Height / 2);
                        else
                            avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y - avatar.Height);
                    }
                    else
                    {
                        ((Button)thing).currentState = Button.State.OFF;
                        if (lastState != Button.State.OFF)
                        {
                            currentMap.changeButtonState();
                            thing.Position.Y -= 10;
                        }
                    }
                }
                else if (thing is GaffaSpawner)
                {
                    rect2 = new Rectangle((int)((GaffaSpawner)thing).Position.X, (int)((GaffaSpawner)thing).Position.Y, thing.Width, thing.Height);
                    if (rect1.Intersects(rect2))
                    {
                        if (avatar.direction == Avatar.Direction.RIGHT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                            avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X - thing.Width / 2 - avatar.Width);
                        else if (avatar.direction == Avatar.Direction.LEFT && avatar.lastPosition.Y < rect2.Bottom && avatar.lastPosition.Y + avatar.Height > rect2.Top)
                            avatar.Position.X = MathHelper.Clamp(avatar.Position.X, avatar.lastPosition.X, thing.Position.X + thing.Width / 2);
                        else if (avatar.action == Avatar.Action.JUMPING)
                            avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y + thing.Height / 2);
                        else
                            avatar.Position.Y = MathHelper.Clamp(avatar.Position.Y, avatar.lastPosition.Y, thing.Position.Y - avatar.Height);
                    }
                }
            }

            if (avatar.lastPosition.Y < avatar.Position.Y)
                avatar.action = Avatar.Action.LANDING;
        }
        private void updateEnemyCollisions()
        {
            Rectangle rect1, rect2;

            foreach (Enemy enemy in currentMap.enemies)
            {
                if (!enemy.Active)
                    continue;
                rect1 = new Rectangle((int)enemy.Position.X, (int)enemy.Position.Y,
                    enemy.Width, enemy.Height);

                foreach (VisualObject thing in currentMap.objects)
                {
                    rect2 = new Rectangle((int)thing.Position.X - thing.Width / 2, (int)thing.Position.Y - thing.Height / 2, thing.Width, thing.Height);
                    if (rect1.Intersects(rect2) && !(thing is GaffaSpawner))
                    {
                        if (enemy.direction == Enemy.Direction.RIGHT && enemy.lastPosition.Y < rect2.Bottom && enemy.lastPosition.Y + enemy.Height > rect2.Top)
                        {
                            enemy.Position.X = MathHelper.Clamp(enemy.Position.X, enemy.lastPosition.X, thing.Position.X - thing.Width / 2 - enemy.Width);
                            enemy.direction = Enemy.Direction.LEFT;
                        }
                        else if (enemy.direction == Enemy.Direction.LEFT && enemy.lastPosition.Y < rect2.Bottom && enemy.lastPosition.Y + enemy.Height > rect2.Top)
                        {
                            enemy.Position.X = MathHelper.Clamp(enemy.Position.X, enemy.lastPosition.X, thing.Position.X + thing.Width / 2);
                            enemy.direction = Enemy.Direction.RIGHT;
                        }
                        else
                            enemy.Position.Y = MathHelper.Clamp(enemy.Position.Y, enemy.lastPosition.Y, thing.Position.Y - thing.Height / 2 - enemy.Height);
                    }
                }

                rect2 = new Rectangle((int)avatar.Position.X, (int)avatar.Position.Y,
                avatar.Width, avatar.Height);

                if (rect1.Intersects(rect2))
                {
                    currentGameState = GameState.DEAD;
                    ekslosjonslyd.Play();
                        avatar.die();

                    winText = "You died! Press F12 to restart.";
                }
            }
        }
        private void updateGravity()
        {
            if (avatar.action == Avatar.Action.JUMPING)
            {
                avatar.Position.Y -= avatar.currentJumpSpeed;
                avatar.currentJumpSpeed -= 2.0f;

                if (avatar.lastAction == Avatar.Action.JUMPING && avatar.currentJumpSpeed <= 0)
                    avatar.action = Avatar.Action.LANDING;
            }
            
            avatar.Position.Y += 10.0f;
            foreach (Enemy enemy in currentMap.enemies)
            {
                enemy.Position.Y += 10.0f;
            }
        }
        private void takeInput()
        {
            previousKeyboardState = currentKeyboardState;
            currentKeyboardState = Keyboard.GetState();
            switch (currentGameState)
            {
                case GameState.GAME:
                    if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyboardState.IsKeyDown(Keys.Space))
                        avatar.InputJump();
                    if (currentKeyboardState.IsKeyDown(Keys.Left))
                        avatar.InputLeft();
                    if (currentKeyboardState.IsKeyDown(Keys.Right))
                        avatar.InputRight();
                    if (currentKeyboardState.IsKeyDown(Keys.Up))
                        avatar.InputUp();
                    if (currentKeyboardState.IsKeyDown(Keys.Down))
                        avatar.InputDown();
                    if (currentKeyboardState.GetPressedKeys().Length == 0)
                        avatar.InputNothing();
                    if (currentKeyboardState.IsKeyDown(Keys.P) && previousKeyboardState != currentKeyboardState)
                        currentGameState = GameState.PAUSE;
                    if (currentKeyboardState.IsKeyDown(Keys.F12))
                        this.Restart();
                    if (currentKeyboardState.IsKeyDown(Keys.Escape))
                    {
                        this.winText = "";
                        this.PlayMusic(menuSong);
                        currentGameState = GameState.MAINMENU;
                    }
                    break;
                case GameState.DEAD:
                    if (currentKeyboardState.IsKeyDown(Keys.F12))
                    {
                        this.Restart();
                        currentGameState = GameState.GAME;
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.Escape))
                    {
                        this.winText = "";
                        currentGameState = GameState.MAINMENU;
                        this.PlayMusic(menuSong);
                    }
                    break;
                case GameState.MAINMENU:
                    if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyboardState.IsKeyDown(Keys.Space))
                    {
                        currentGameState = menu.InputSelect();
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState != currentKeyboardState)
                        menu.InputUp();
                    else if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState != currentKeyboardState)
                        menu.InputDown();
                    break;
                case GameState.OPTIONS:
                    if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyboardState.IsKeyDown(Keys.Space))
                    {
                        switch (optionsScreen.InputSelect())
                        {
                            case OptionsScreen.OptionsChoice.TOGGLE_MUSIC:
                                musicEnabled = !musicEnabled;
                                this.PawsMusic();
                                select.Play();
                                break;
                            case OptionsScreen.OptionsChoice.BACK:
                                back.Play();
                                currentGameState = GameState.MAINMENU;
                                break;
                        }
                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState != currentKeyboardState)
                        optionsScreen.InputUp();
                    else if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState != currentKeyboardState)
                        optionsScreen.InputDown();
                    else if (currentKeyboardState.IsKeyDown(Keys.Escape) && previousKeyboardState != currentKeyboardState)
                    {
                        currentGameState = GameState.MAINMENU;
                        optionsScreen.InputEsc();
                    }
                    break;
                case GameState.MAPSELECT:
                    if (currentKeyboardState.IsKeyDown(Keys.Space) && !previousKeyboardState.IsKeyDown(Keys.Space))
                    {
                        switch (mapSelectScreen.InputSelect())
                        {
                            case MapSelectScreen.MapSelectChoice.TESTMAP:
                                currentMap = new TestMap();
                                break;
                            case MapSelectScreen.MapSelectChoice.TESTMAP2:
                                
                                currentMap = new TestMap2();
                                break;
                            case MapSelectScreen.MapSelectChoice.BACK:
                                back.Play();
                                currentGameState = GameState.MAINMENU;
                                return;
                        }
                        currentMap.Initialize(Content, GraphicsDevice.Viewport);
                        
                        avatar.Initialize(GraphicsDevice.Viewport, Content, currentMap.avatarStartPosition, AnimatedObject.Direction.RIGHT);
                        this.PlayMusic(gameSong);
                        
                        currentGameState = GameState.GAME;

                    }
                    else if (currentKeyboardState.IsKeyDown(Keys.Up) && previousKeyboardState != currentKeyboardState)
                        mapSelectScreen.InputUp();
                    else if (currentKeyboardState.IsKeyDown(Keys.Down) && previousKeyboardState != currentKeyboardState)
                        mapSelectScreen.InputDown();
                    else if (currentKeyboardState.IsKeyDown(Keys.Escape) && previousKeyboardState != currentKeyboardState)
                    {
                        currentGameState = GameState.MAINMENU;
                        optionsScreen.InputEsc();
                    }
                    break;
                case GameState.PAUSE:
                    if (currentKeyboardState.IsKeyDown(Keys.P) && previousKeyboardState != currentKeyboardState)
                        currentGameState = pauseScreen.InputPause();
                    break;
            }
        }

        private void Restart()
        {
            currentMap.Restart(avatar);
            winText = "";
        }
        private void checkForLevelEnd()
        {
            ENDING end = currentMap.IsEnd(avatar, GraphicsDevice.Viewport);
            switch (end)
            {
                case ENDING.WIN:
                    winText = "You win!";
                    currentGameState = GameState.DEAD;
                    break;
                case ENDING.LOSE:
                    winText = "You died! Press F12 to restart.";
                    ekslosjonslyd.Play();
                    currentGameState = GameState.DEAD;
                    break;
                case ENDING.NOTYET:
                    break;
            }
        }
        private void PlayMusic(Song song)
        {
            if (musicEnabled == false)
                return;
            try
            {
                MediaPlayer.Play(song);
                MediaPlayer.IsRepeating = true;
            }
            catch { }
        }
        private void PawsMusic()
        {
            if (musicEnabled)
                MediaPlayer.Resume();
            else
                MediaPlayer.Pause();
        }
    }
}
